#ifndef __SELECT_SVR_H__
#define __SELECT_SVR_H__

#include <iostream>
#include <string>
#include <vector>
#include <sys/select.h> // 包含select系统调用相关定义
#include <sys/time.h>   // 包含timeval结构体用于超时设置
#include "Log.hpp"      // 自定义日志模块头文件
#include "Sock.hpp"     // 自定义套接字操作模块头文件

// 计算单个fd_set能表示的文件描述符数量，假设fd_set为int类型且大小固定
#define BITS 8
#define NUM (sizeof(fd_set) * BITS) // 计算整个fd_set能容纳的文件描述符总数
#define FD_NONE -1                  // 表示无效的文件描述符索引

using namespace std;

// SelectServer类实现基于select的简单多路复用服务器
class SelectServer
{
public:
    // 构造函数，初始化监听端口，默认为8080
    SelectServer(const uint16_t &port = 8080) : _port(port)
    {
        _listensock = Sock::Socket();                          // 创建监听套接字
        Sock::Bind(_listensock, _port);                        // 绑定端口
        Sock::Listen(_listensock);                             // 开始监听
        logMessage(DEBUG, "%s", "create base socket success"); // 日志记录成功创建基础套接字
        // 初始化文件描述符数组
        for (int i = 0; i < NUM; i++)
            _fd_array[i] = FD_NONE;
        // 将监听套接字存入数组第一位
        _fd_array[0] = _listensock;
    }

    // 启动服务器主循环，持续监听并处理连接与数据
    void Start()
    {
        while (true)
        {
            DebugPrint();            // 打印当前监控的文件描述符状态
            fd_set rfds;             // 读事件集合
            FD_ZERO(&rfds);          // 清零集合
            int maxfd = _listensock; // 当前最大文件描述符

            // 将有效文件描述符加入集合，并更新maxfd
            for (int i = 0; i < NUM; i++)
            {
                if (_fd_array[i] != FD_NONE)
                {
                    FD_SET(_fd_array[i], &rfds);
                    if (maxfd < _fd_array[i])
                        maxfd = _fd_array[i];
                }
            }

            // 调用select等待事件发生
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);

            // 根据select返回值处理不同情况
            switch (n)
            {
            case 0: // 超时
                logMessage(DEBUG, "%s", "time out...");
                break;
            case -1: // 错误
                logMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
                break;
            default: // 成功
                logMessage(DEBUG, "get a new link event...");
                HandlerEvent(rfds); // 处理就绪事件
                break;
            }
        }
    }

    // 析构函数，关闭监听套接字
    ~SelectServer()
    {
        if (_listensock >= 0)
            close(_listensock);
    }

private:
    // 事件处理函数
    void HandlerEvent(const fd_set &rfds)
    {
        for (int i = 0; i < NUM; i++)
        {
            if (_fd_array[i] != FD_NONE && FD_ISSET(_fd_array[i], &rfds))
            {
                if (_fd_array[i] == _listensock) // 监听套接字有连接请求
                    Accepter();
                else // 已连接的套接字有数据可读
                    Recver(i);
            }
        }
    }

    // 接受新连接
    void Accepter()
    {
        string clientip;
        uint16_t clientport = 0;
        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s:%d] : %d", clientip.c_str(), clientport, sock);

        // 将新连接的套接字加入监控
        int pos = 1;
        for (; pos < NUM && _fd_array[pos] != FD_NONE; pos++)
            ; // 查找空位
        if (pos == NUM)
        {
            logMessage(WARNING, "select server full, close: %d", sock);
            close(sock);
        }
        else
        {
            _fd_array[pos] = sock;
        }
    }

    // 处理接收数据
    void Recver(int pos)
    {
        logMessage(DEBUG, "message in, get IO event: %d", _fd_array[pos]);

        char buffer[1024];
        int n = recv(_fd_array[pos], buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fd_array[pos], buffer);
        }
        else if (n == 0)
        { // 客户端关闭连接
            logMessage(DEBUG, "client[%d] quit, me too...", _fd_array[pos]);
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fd_array[pos], errno, strerror(errno));
            close(_fd_array[pos]);
            _fd_array[pos] = FD_NONE;
        }
    }

    // 打印当前监控的文件描述符数组状态，供调试用
    void DebugPrint()
    {
        cout << "_fd_array[]: ";
        for (int i = 0; i < NUM; i++)
        {
            if (_fd_array[i] != FD_NONE)
                cout << _fd_array[i] << " ";
        }
        cout << endl;
    }

    // 私有成员变量
    uint16_t _port;     // 监听端口
    int _listensock;    // 监听套接字描述符
    int _fd_array[NUM]; // 存储所有被监控的文件描述符的数组
};

#endif // __SELECT_SVR_H__